/*
 * Copyright 2009, Team Mondegreen:
 * Brian Hsieh - bh2181@columbia.edu
 * Eugene Yao - eyy2102@columbia.edu
 * Jake Amonette - jaa2149@columbia.edu
 * Tal Giat - tg2235@colubia.edu
 * 
 * This file is part of AMFM (A Minimal Fractal Music Language), a language created for
 * fractal music as part of the Programming Languages and Translator class at Columbia university.
 *
 * For more details go to: http://code.google.com/p/amfm/
 * 
 * AMFM is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * at your option any later version.
 * 
 * AMFM is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with AMFM.  If not, see <http://www.gnu.org/licenses/>. 
 */

package com.myronmarston.music.settings;

import org.simpleframework.xml.Root;

import com.myronmarston.music.Instrument;
import com.myronmarston.music.NoteList;
import com.myronmarston.music.NoteStringParseException;
import com.myronmarston.music.Tempo;
import com.myronmarston.music.scales.Scale;

/**
 * This class holds AmFm seeds. It holds the instrument and the germ for the seed.
 * 
 * @author Jake
 */
@Root
public class AmFmSeed {
  private NoteList germ = new NoteList().getReadOnlyCopy();

  private String germString = "";

  /** Currently tempo is constant and set to 90 future version can enable different tempo */
  private int tempo = Tempo.DEFAULT;

  /** Currently scale is chromatic future version can enable more scales */
  private Scale scale = Scale.DEFAULT;

  /**
   * The only constructor you must provide valid germ string, and a valid instrument
   * 
   * @param germString the germ string to set, one that is written based on fractal composer syntax 
   * @param instrument the instrument for the seed, if null is passed the default instrument will be used (piano)
   * @throws NoteStringParseException if an invalid note string was given an input one that does not conform
   *           to the AmFm note unit syntax
   * @throws IllegalArgumentException if a null note string was provided
   */
  public AmFmSeed(String germString, Instrument instrument) throws NoteStringParseException,
      IllegalArgumentException {
    if (germString == null) {
      throw new IllegalArgumentException("germ string cannot be null");
    }
    Instrument inst = (instrument == null ? Instrument.DEFAULT : instrument);
    setGermString(germString, inst);
  }

  /**
   * Returns the germ NoteList. Guaranteed to never be null. Is read-only. The germ is the short melody from
   * which the entire piece is generated.
   * 
   * @return the germ NoteList
   */
  public NoteList getGerm() {
    assert germ != null : germ; // germ should never be null!

    // the germ should be read-only because we only support changing it
    // through the setGermString() method. Our section cached germs
    // must be updated when the germ changes, and it's easiest to only
    // do that the germ string changes
    assert germ.isReadOnly();
    return germ;
  }

  /**
   * Gets the germ string.
   * 
   * @return the germ string
   */
  public String getGermString() {
    assert germString != null : germString; // germString should never be null!
    return germString;
  }

  /**
   * Sets the notes for the germ.
   * 
   * @param germString string containing a list of notes
   * @throws com.myronmarston.music.NoteStringParseException if the note list string cannot be parsed
   * @throws IllegalArgumentException if instrument is null
   */
  private void setGermString(String germString, Instrument instrument) throws NoteStringParseException, IllegalArgumentException {
    NoteList noteList = NoteList.parseNoteListString(germString, this.getScale());
    noteList.setInstrument(instrument);
    this.germ = noteList.getReadOnlyCopy();
    this.germString = germString;
  }

  /**
   * Gets the tempo of the piece, in beats per minute.
   * 
   * @return the tempo of the piece
   */
  public int getTempo() {
    return tempo;
  }

  /**
   * Returns the Scale. The Scale is used to determine the tonality of the piece, and will also be used to set
   * the key signature of the Midi sequence.
   * 
   * @return the Scale used by this FractalPiece
   */
  public Scale getScale() {
    assert scale != null : scale; // scale should never be null!
    return scale;
  }  
}
